package com.paul.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.paul.jwt.config.JwtConfig;
import com.paul.jwt.dto.AuthPrincipal;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Date;
import java.util.Map;
import java.util.Random;


public class JWTUtil {

    private static final Logger logger = LoggerFactory.getLogger(JWTUtil.class);

    /**
     * 校验token是否正确
     *
     * @param authPrincipal 用户对象
     * @return 是否正确
     */
    public static boolean verify(AuthPrincipal authPrincipal, String token, JwtConfig config) {
        try {
//            System.out.println("SECRET:" + config.getJwtSecret());
            Algorithm algorithm = Algorithm.HMAC256(config.getJwtSecret());
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("userId", authPrincipal.getUserId())
                    .withClaim("sysAuthType", authPrincipal.getSysAuthType())
                    .withClaim("PayLoad", authPrincipal.getPayLoad().toString())
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static Claim getClaim(String token, String claimName) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(claimName);
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static AuthPrincipal getAuthUser(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            Map<String, Claim> claims = jwt.getClaims();
//            System.out.println("claims size:"+claims);
            if (claims.size() > 0 && checkClaimsIsNull(claims)) {
                AuthPrincipal authPrincipal = new AuthPrincipal();
                authPrincipal.setUserId(claims.get("userId").asLong());
                authPrincipal.setSysAuthType(claims.get("sysAuthType").asInt());
                authPrincipal.setPayLoad(claims.get("PayLoad"));
                return authPrincipal;
            }
            return null;
        } catch (JWTDecodeException e) {
//            System.out.println("获取用户信息出现异常");
//            e.printStackTrace();
            return null;
        }
    }

    private static boolean checkClaimsIsNull(Map<String, Claim> claims) {
        if (claims.get("sysAuthType") == null) return false;
        if (claims.get("PayLoad") == null) return false;
        return claims.get("userId") != null;
    }

    /**
     * 生成签名,5min后过期
     *
     * @param authPrincipal 用户对象
     * @return 加密的token
     */
    public static String sign(AuthPrincipal authPrincipal, Date date, JwtConfig config) {

        Algorithm algorithm = Algorithm.HMAC256(config.getJwtSecret());
        // 附带username信息
        return JWT.create()
                .withClaim("userId", authPrincipal.getUserId())
                .withClaim("sysAuthType", authPrincipal.getSysAuthType())
                .withClaim("PayLoad", authPrincipal.getPayLoad().toString())
                .withExpiresAt(date)
                .sign(algorithm);

    }

    public static Date getExpireTime(String userAgent, String source, JwtConfig config) {
        Long expireTime = isMobileDevice(userAgent, source) ? config.getJwtExpireTimeMobile() : config.getJwtExpireTime();
        return new Date(System.currentTimeMillis() + expireTime);
    }

    /**
     * 判断请求来自手机端还是电脑端
     */
    private static boolean isMobileDevice(String userAgent, String source) {
        /*
         * android            :所有安卓设备
         * mas  os            :iphone
         * windows phone    :windows系统手机
         */
        String[] deviceArray = new String[]{"android", "mas os", "windows phone"};
        if (null == userAgent) {
            return false;
        }
        userAgent = userAgent.toLowerCase();
        for (String aDeviceArray : deviceArray) {
            if (userAgent.indexOf(aDeviceArray) >= 0) {
                return true;
            }
        }

        if (!StringUtils.isBlank(source) && source.indexOf("h5") >= 0) {
            System.out.println("is h5 login");
            return true;
        }
        return false;
    }

    /**
     * 生成refersh token
     */
    public static String generateRefreshToken() {
        String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
        try {
            MessageDigest md = MessageDigest.getInstance("md5");
            byte md5[] = md.digest(token.getBytes());
//            BASE64Encoder encoder = new BASE64Encoder();
//            return encoder.encode(md5);
            return Base64.getEncoder().encodeToString(md5);
        } catch (NoSuchAlgorithmException e) {
            logger.error("generateRefreshToken exception:", e);
        }
        return null;
    }
}
